import { Compiler, Component, ComponentFactory, Injectable, NgModule } from '@angular/core';
import {
    FieldType,
    FormField
} from '@shared/service-proxies/service-proxies';

import { AppLocalizationService } from '@app/shared/common/localization/app-localization.service';
import { HtmlHelper } from '@shared/helpers/HtmlHelper';
import { DateTime } from 'luxon';
import { DateTimeHelper } from '@shared/helpers/DateTimeHelper';
import { AppSharedModule } from '@app/shared/app-shared.module';
import { MainSharedModule } from './main-shared.module';
import { LayoutEditorModule } from './layout-edtor/layout-editor.module';
import { FileUploadHelper } from '@shared/helpers/FileUploadHelper';

@Injectable()
export class DiyFormService {

    constructor(
        private _appLocalizationService: AppLocalizationService) {

    }

   
    beforeSubmit(config: FormField[], field: { [key: string]: any }) {
        let thisDefs: FormField;
        for (let i = 0; i < config.length; i++) {
            thisDefs = config[i];
            if (thisDefs.fieldType === FieldType.DateTime) {
                // 转时间戳
                let dateTimeVal = field[thisDefs.fieldName];
                let dateTime = dateTimeVal as DateTime;
                field[thisDefs.fieldName] = DateTimeHelper.ToUnixTimeByMilliseconds(dateTime);
            }
            else if (this.isHtmlCtrl(thisDefs)) {
                // 编码
                let htmlVal = field[thisDefs.fieldName];
                field[thisDefs.fieldName] = HtmlHelper.htmlEncode(htmlVal);
            } else if (thisDefs.fieldType === FieldType.Enum && thisDefs.ctrlType === "CheckBox") {
                let enumArr = field[thisDefs.fieldName];
                let enumArr2 = [];
                for (let jj = 0; jj < enumArr.length; jj++) {
                    if (enumArr[jj])
                        enumArr2.push(jj);
                }
                field[thisDefs.fieldName] = enumArr2.join(',');
            } else if (thisDefs.fieldType === FieldType.Taxonomy || thisDefs.fieldType === FieldType.TaxonomyByValue) {
                let isMulti = false;
                if (thisDefs.security) {
                    if (thisDefs.security.multiSeleted) {
                        isMulti = true;
                    }
                }
                if (isMulti) {
                    let taxonomyArr = field[thisDefs.fieldName];
                    if(taxonomyArr){
                        let dataArr =  taxonomyArr.split(',');
                        var filtered = [];
                        dataArr.forEach(tt => {
                            if (tt) {
                                filtered.push(tt);
                            }
                        });
                        field[thisDefs.fieldName] = ',' + filtered.join(',') + ',';
                    }else{
                        field[thisDefs.fieldName] = '';
                    }
                }
            }
        }
    }

    afterLoadData(config: FormField[], data: { [key: string]: any }) {
        let thisDefs: FormField;

        for (let i = 0; i < config.length; i++) {
            thisDefs = config[i];
            if (thisDefs.fieldType === FieldType.DateTime) {
                // 时间戳转DateTime
                let dateTimeVal = data[thisDefs.fieldName];
                try {
                    dateTimeVal = parseInt(dateTimeVal);
                } catch (e) {
                    dateTimeVal = 0;
                }

                //moment(dateTimeVal).format(thisDefs.customData.split('|')[0]);
                if (dateTimeVal == 0){
                    data[thisDefs.fieldName] = null;
                }
                else{
                    data[thisDefs.fieldName] = DateTimeHelper.FromUnixTimestampByMilliseconds(dateTimeVal); 
                }
            }
            else if (this.isHtmlCtrl(thisDefs)) {
                // 解码
                let htmlVal = data[thisDefs.fieldName];
                data[thisDefs.fieldName] = HtmlHelper.htmlDecode(htmlVal);
            } else if (thisDefs.fieldType === FieldType.Enum && thisDefs.ctrlType === "CheckBox") {
                let enumVal = data[thisDefs.fieldName];
                let enumValLength = thisDefs.customData.split("|").length - 1;
                let enumArr = [];
                for (let jj = 0; jj < enumValLength; jj++) {
                    if (("," + enumVal + ",").indexOf("," + jj + ",") > -1) {
                        enumArr[jj] = true;
                    }
                    else {
                        enumArr[jj] = false;
                    }
                }
                data[thisDefs.fieldName] = enumArr;
            } else if (thisDefs.fieldType === FieldType.Taxonomy || thisDefs.fieldType === FieldType.TaxonomyByValue) {

            } else if (thisDefs.fieldType === FieldType.Input) {
                let inputVal = data[thisDefs.fieldName];
                if ("date|datetime-local|month|week|time".indexOf(thisDefs.ctrlType) >= 0) {
                    //转datetime
                    data[thisDefs.fieldName] = DateTimeHelper.FromUnixTimestampByMilliseconds(Number(inputVal as string));;
                } else if (thisDefs.ctrlType === "range") {
                    //?
                    data[thisDefs.fieldName] = parseInt(inputVal);
                }
            }
        }
    }

    getDetailPageTemplate(config: FormField[], subKey: string = null) :string {
        let groupNameList = Array.from(new Set(config.map(t=>t.groupName)));
        let str : string;

        let dataStr = subKey? "data['"+subKey+"'].":"data." ;

        if(groupNameList.length < 2){
            str = this.getDetailPageFormHtml(config, dataStr ,subKey);
            return str + this.getHtmlForDataSynchronous(dataStr) + this.appendTemplateHtml();
        }

        str = "<tabset>";
        
        for(let i =0 ; i< groupNameList.length; i++){
            let groupName = groupNameList[i];
            let tabConfig = config.filter(item=> item.groupName === groupName);
            if(!groupName){
                groupName = "基本信息";
            }
            str += "    <tab class=\"pt-3\" heading=\"{{'"+groupName+"'|localize}}\" >";
            
            str += this.getDetailPageFormHtml(tabConfig, dataStr ,subKey);
            str += "    </tab>";
        } 

        str += "    <tab class=\"pt-3\" heading=\"{{'DataSynchronous'|localize}}\" *ngIf=\"dataSynchronous\">"
        str += this.getHtmlForDataSynchronous(dataStr);
        str += "    </tab>";

        str += "</tabset>";
        return str + this.appendTemplateHtml();
    }

    private getDetailPageFormHtml(config: FormField[], dataStr: string , subKey: string) :string {
        let str = "",
            colNum = 0,
            length = config.length;
        let thisField: FormField;

        let newRowOpen = false;
        for (let i = 0; i < length; i++) {
            thisField = config[i];

            if(thisField.fieldType ===  FieldType.NewLine){
                if(newRowOpen){
                    str += "</div>"  //一行结束
                    colNum = 0;
                    newRowOpen = false;
                    continue;
                }else{
                    //占位一行（分割线）
                    str += "<div class=\"row\"><hr/></div>"; 
                    colNum = 0;
                    newRowOpen = false;
                    continue;
                }
            }

            if(thisField.fieldType === FieldType.PlaceHold){
                continue;
            }

            if ((colNum + thisField.ctrlWidth > 12) && newRowOpen) {
                str += "</div>"  //一行结束
                colNum = 0;
                newRowOpen = false;
            }
            if (colNum === 0) {
                newRowOpen = true;
                str += "<div class=\"row\">";
            }

            if (this.isHtmlCtrl(thisField) && thisField.customData) {
                //自动合并具有相同customData的富文本编辑框
                let uuid = thisField.customData;
                let arr: FormField[] = [];

                while (i < length && this.isHtmlCtrl(config[i]) && uuid === config[i].customData) {
                    arr.push(config[i]);
                    i++;
                }

                if (arr.length === 1) {
                    str += this.getHtmlForText(thisField,dataStr);
                } else {
                    str += this.getHtmlForText2(arr,dataStr);
                }

                i--;
            } else {
                str += this.getHtmlForCtrl(thisField, i, dataStr, subKey);
            }
            colNum += thisField.ctrlWidth;
        }

        if(newRowOpen){
            str += "</div>"
        }

        return str;
    }

    //TODO 待测试
    private getDiyAttibutes(thisField: FormField){
        if(thisField.attributes){
            return " " + thisField.attributes.replace(/\"/g, '\"') +  " ";
        }
        return "";
    }

    private isHtmlCtrl(thisField: FormField) {
        if (thisField.fieldType === FieldType.Text && thisField.ctrlType !== "Text") {
            return true;
        }
        return false;
    }

    private appendTemplateHtml(){
        return "<ng-template #htmlTextTemplate><div [innerHtml]=\"'HtmlRules_Hint' | localizeAndTrustAs :'html'\"></div></ng-template>";
    }

    private addhelpText(ctrlStr: string, helperStr: string) {
        if (helperStr) {
            let str = "";
            str += "<div class=\"input-icon input-icon-sm right\">";
            str += "    <i class=\"fa fa-question-circle\"  tooltip=\"" + this._appLocalizationService.l(helperStr) + "\" placement=\"top\"></i>";
            str += ctrlStr;
            str += "</div>";
            return str;
        } else {
            return ctrlStr;
        }
    }

    
    private getColumnHtml(thisDefs: FormField, ctrlStr: string, className: string) {
        let str = "<div class=\"col-sm-" + thisDefs.ctrlWidth + " "+ className +"\"";
        if (thisDefs.showOrNot) {
            str += " *ngIf=\"" + thisDefs.showOrNot + "\"";
        }
        str += ">";
        str += ctrlStr;
        str += "</div>";
        return str;
    }

    private getHtmlForCtrl(thisDefs: FormField, i: number, dataStr: string, subKey: string) {
        if (thisDefs.fieldType === FieldType.Boolean) {
            return this.getHtmlForBoolean(thisDefs,dataStr);
        }
        else if (thisDefs.fieldType === FieldType.Enum) {
            return this.getHtmlForEnum(thisDefs,dataStr);
        }
        else if (thisDefs.fieldType === FieldType.Taxonomy) {
            return this.getHtmlForTaxonomy(thisDefs,dataStr, false);
        }
        else if (thisDefs.fieldType === FieldType.Input) {
            return this.getHtmlForInput(thisDefs,dataStr);
        }
        else if (thisDefs.fieldType === FieldType.Text) {
            return this.getHtmlForText(thisDefs,dataStr);
        }
        else if (thisDefs.fieldType === FieldType.DateTime) {
            return this.getHtmlForDateTime(thisDefs,dataStr);
        }
        else if (thisDefs.fieldType === FieldType.Number) {
            return this.getHtmlForNumber(thisDefs,dataStr);
        }
        else if (thisDefs.fieldType === FieldType.File) {
            return this.getHtmlForFile(thisDefs,dataStr, subKey);
        }
        else if (thisDefs.fieldType === FieldType.TaxonomyByValue) {
            return this.getHtmlForTaxonomy(thisDefs,dataStr, true);
        }        
        else if (thisDefs.fieldType === FieldType.Layout) {
            return this.getHtmlForLayout(thisDefs, dataStr);
        }
        else if (thisDefs.fieldType === FieldType.Radio) {
            return this.getHtmlForRadio(thisDefs, dataStr);
        }
        else if (thisDefs.fieldType === FieldType.Span) {
            return this.getHtmlForSpan(thisDefs, dataStr);
        }


        return "";
    }

    private getHtmlForDataSynchronous(dataStr: string){
        let str = "";
        str += "<div class=\"row\" *ngIf=\"dataSynchronous\">";
        str += "    <div class=\"col-sm-6\">";

        let id =  FileUploadHelper.randomId();

        str += "<div class=\"form-group form-md-line-input form-md-floating-label no-hint\">";
        str += "<label for=\"autoSync"+id+"\" class=\"checkbox\">";
        str += this._appLocalizationService.l('AutoSynchronous') 
        str += "    <input id=\"autoSync"+id+"\" class=\"md-check\"";
        str += "           type=\"checkbox\" name=\"autoSynchronous\"";
        str += "           [(ngModel)]=\""+dataStr +"autoSynchronous\">";
        str += "    <span></span>";
        str += "</label>";
        str += "</div>";

        str += "    </div>";
        str += "    <div class=\"col-sm-6\"></div>";
        str += "</div>";
        return str; 
    }

    private getHtmlForLayout(thisDefs: FormField, dataStr: string) {
        // 仅实现两种ctrlType: Text，Html,
        let ctrlStr = "<div class=\"form-group\">";
        ctrlStr += "    <layout-editor title=\"" + this._appLocalizationService.l(thisDefs.displayName) + "\" [(data)]=\""+dataStr + thisDefs.fieldName + "\"></layout-editor>";
        ctrlStr += "</div>";

        return this.getColumnHtml(thisDefs, ctrlStr, '');
    }

    private getHtmlForText(thisDefs: FormField, dataStr: string) {
        // 仅实现两种ctrlType: Text，Html,
        let ctrlStr = "";
        if (thisDefs.ctrlType === "Text") {
            ctrlStr += "<div class=\"form-group form-md-line-input form-md-floating-label no-hint\">"; 
            if (thisDefs.security && thisDefs.security.maxLength) {
                ctrlStr += "<label>" + this._appLocalizationService.l(thisDefs.displayName) + "({{"+dataStr + thisDefs.fieldName+"?"+dataStr + thisDefs.fieldName+".length:0}}/"+thisDefs.security.maxLength+")</label> ";
            }else{
                ctrlStr += "<label>" + this._appLocalizationService.l(thisDefs.displayName) + "</label> ";
            }

            ctrlStr += "    <textarea rows=\"" + (thisDefs.customData ? thisDefs.customData : "3") + "\" class=\"form-control form-control-text\" name=\"" + thisDefs.fieldName + "\" "
            if (thisDefs.security) {
                if (thisDefs.security.required) {
                    ctrlStr += " required ";
                }
                if (thisDefs.security.maxLength) {
                    ctrlStr += " maxlength=\"" + thisDefs.security.maxLength + "\" ";
                }
            }
            if(thisDefs.readOnly){
                ctrlStr += " readOnly "; 
            }
            ctrlStr += " [ngClass]=\"{'edited':data." + thisDefs.fieldName + "}\" [(ngModel)]=\""+dataStr + thisDefs.fieldName + "\" ></textarea>";
            ctrlStr += "</div>";

            let str = "<div class=\"col-sm-" + thisDefs.ctrlWidth + "\">";
            str += this.addhelpText(ctrlStr, thisDefs.helpText);
            str += "</div>";
            return str;
        } else {
            let height = 0;
            if(thisDefs.customData2){
                try{
                   const json = JSON.parse(thisDefs.customData2);
                   if(json['height']){
                     height = parseInt(json['height']);
                   }
                }catch{}
            } 
            ctrlStr += "<div class=\"form-group\">";
            ctrlStr += "    <label>" + this._appLocalizationService.l(thisDefs.displayName) + "</label>";
            ctrlStr += "    <ckeditor [(data)]=\""+dataStr + thisDefs.fieldName + "\"";
            if(height){
                ctrlStr += " height=\""+ height +"\"";
            }
            ctrlStr += "></ckeditor>";
            ctrlStr += "</div>";

            if(thisDefs.helpText){
                return this.getColumnHtml(thisDefs, this.addhelpText(ctrlStr, thisDefs.helpText), '');
            }else{
                let str = "<div class=\"input-icon input-icon-sm right\">";
                str += "    <i class=\"fa fa-question-circle\"  [tooltip]=\"htmlTextTemplate\" placement=\"top\"></i>";
                str += ctrlStr;
                str += "</div>";

                return this.getColumnHtml(thisDefs, str, '');
            }
        }
    }

    private getHtmlForText2(arr: FormField[], dataStr: string) {
        let ctrlStr = "";
        let thisDefs: FormField;

        ctrlStr += "    <tabset class=\"ui-tabs-nav\">";
        for (let i = 0; i < arr.length; i++) {
            thisDefs = arr[i];
            ctrlStr += "        <tab heading=\"" + this._appLocalizationService.l(thisDefs.displayName) + "\">";
            ctrlStr += "            <div class=\"row\">";
            if (thisDefs.helpText) {
                ctrlStr += "            <div class=\"col-sm-12\">";
                ctrlStr += "                <label class=\"form-control margin-bottom-5\" disabled>&nbsp;&nbsp;&nbsp;" + this._appLocalizationService.l(thisDefs.helpText) + "</label>";
                ctrlStr += "            </div>";
            }
            ctrlStr += "            <div class=\"col-sm-12\">";
            ctrlStr += "                <ckeditor [(data)]=\""+dataStr + thisDefs.fieldName + "\"></ckeditor>";
            ctrlStr += "            </div>";
            ctrlStr += "            </div>";
            ctrlStr += "        </tab>";
        }
        ctrlStr += "    </tabset>";

        return this.getColumnHtml(thisDefs, ctrlStr , 'form-group');
    }

    private getHtmlForBoolean(thisDefs: FormField, dataStr: string) {
        let ctrlStr = "";
        let id =  'i' +FileUploadHelper.randomId();

        ctrlStr += "<div class=\"form-group form-md-line-input \">";
        ctrlStr += "<label for=\"" + id + "\" class=\"checkbox\">";
        ctrlStr += "    <input id=\"" + id + "\" class=\"md-check\"";
        ctrlStr += "           type=\"checkbox\" name=\"" + thisDefs.fieldName + "\"";
        ctrlStr += "           [(ngModel)]=\""+dataStr + thisDefs.fieldName + "\">";
        ctrlStr += "    <span>&nbsp;</span>";
        ctrlStr += this._appLocalizationService.l(thisDefs.displayName);
        ctrlStr += "</label>";
        ctrlStr += "</div>";

        return this.getColumnHtml(thisDefs, this.addhelpText(ctrlStr, thisDefs.helpText), 'form-group');
    }

    private getHtmlForSpan(thisDefs: FormField, dataStr: string) {
        let ctrlStr = "";
        let id =  'i' +FileUploadHelper.randomId();

        ctrlStr += "<div class=\"form-group form-md-line-input form-md-floating-label no-hint \">";
        ctrlStr += "<label>" + this._appLocalizationService.l(thisDefs.displayName) + "</label> ";
        ctrlStr += "<span style='margin-left:12px;'>{{" +dataStr + thisDefs.fieldName + "}}</span>";
        ctrlStr += "</div>";

        return this.getColumnHtml(thisDefs, this.addhelpText(ctrlStr, thisDefs.helpText), 'form-group');
    }

    private getHtmlForRadio(thisDefs: FormField, dataStr: string) {
        // labelName*value|lableName*valuve|4
        let id =  'i' +FileUploadHelper.randomId();
        let ctrlStr = "", values;

        values = thisDefs.customData.split('|');
        let colSpan = parseInt(values[values.length - 1]);

        let colNum = 0;
        for (let i = 0; i < values.length - 1; i++) {
            if (colNum + colSpan > 12) {
                ctrlStr += "</div>"  //一行结束
                colNum = 0;
            }
            if (colNum === 0) {
                ctrlStr += "<div class=\"row\">";
            }

            let val = values[i].split('*');

            ctrlStr += "<div class=\"col-sm-" + colSpan + "\">";
            ctrlStr += "<div class=\"form-group form-md-line-input \">";
            ctrlStr += "<label for=\"" + id +i+ "\" class=\"radio\">";
            ctrlStr += "    <input id=\"" + id +i + "\" class=\"md-radio\"";
            ctrlStr += "           type=\"radio\" name=\"" + thisDefs.fieldName + "\" value=\"" + val[1] + "\"";
            ctrlStr += "           [(ngModel)]=\""+dataStr + thisDefs.fieldName + "\" [checked]=\""+dataStr + thisDefs.fieldName + "==='" + val[1] + "'\">";
            ctrlStr += "    <span>&nbsp;</span>";
            ctrlStr += this._appLocalizationService.l(val[0]);
            ctrlStr += "</label>";
            ctrlStr += "</div>";
            
            ctrlStr += "</div>";
            colNum += colSpan;
        }
        ctrlStr += "</div>";

        return this.getColumnHtml(thisDefs, ctrlStr, '');
    }

    // checkbox (待调整)
    private getHtmlForEnum(thisDefs: FormField, dataStr: string) {
        let id =  'i' +FileUploadHelper.randomId();
        // 仅实现两种ctrlType: Selection（单选），CheckBox（多选）
        let ctrlStr = "", values;

        if (thisDefs.ctrlType === "CheckBox") {
            values = thisDefs.customData.split('|');
            let colSpan = Math.ceil(12.0 / parseInt(values[values.length - 1]));

            ctrlStr += "<div class=\"form-group\">";
            ctrlStr += "    <label>" + this._appLocalizationService.l(thisDefs.displayName) + "</label>";
            let colNum = 0;
            for (let i = 0; i < values.length - 1; i++) {
                if (colNum + colSpan > 12) {
                    ctrlStr += "</div>"  //一行结束
                    colNum = 0;
                }
                if (colNum === 0) {
                    ctrlStr += "<div class=\"row\">";
                }

                ctrlStr += "<div class=\"col-sm-" + colSpan + "\">";

                ctrlStr += "<div class=\"form-group form-md-line-input form-md-floating-label no-hint\">";
                ctrlStr += "<label for=\"" + id + i + "\" class=\"checkbox\">";
                ctrlStr += this._appLocalizationService.l(values[i]);
                ctrlStr += "    <input id=\"" + id + i + "\" class=\"md-check\"";
                ctrlStr += "           type=\"checkbox\" name=\"" + thisDefs.fieldName + "\"";
                ctrlStr += "           [(ngModel)]=\""+dataStr + thisDefs.fieldName + "[" + i + "]\">";
                ctrlStr += "    <span></span>";
                ctrlStr += "</label>";
                ctrlStr += "</div>";
                
                ctrlStr += "</div>";
                colNum += colSpan;
            }
            ctrlStr += "</div>";
            ctrlStr += "</div>";
        }
        else {
            ctrlStr += "<div class=\"form-group form-md-line-input form-md-floating-label no-hint\">";
            ctrlStr += "    <label for=\"" + id + "\">" + this._appLocalizationService.l(thisDefs.displayName) + "</label>";

            ctrlStr += "    <select id=\"" + id + "\"  name=\"" + thisDefs.fieldName + "\"  class=\"form-control edited\"   [(ngModel)]=\""+dataStr + thisDefs.fieldName + "\">";
            let required = false;
            if (thisDefs.security) {
                if (thisDefs.security.required) {
                    required = true;
                }
            }
            if (!required) {
                ctrlStr += "        <option value=\"\">-- " + this._appLocalizationService.l("EmptyOnes") + " --</option>";
            }
            values = thisDefs.customData.split('|');
            for (let i = 0; i < values.length - 1; i = i + 2) {
                ctrlStr += "        <option value=\"" + values[i + 1] + "\">" + this._appLocalizationService.l(values[i]) + "</option>";
            }
            ctrlStr += "    </select>";
            ctrlStr += "</div>";
        }

        return this.getColumnHtml(thisDefs, this.addhelpText(ctrlStr, thisDefs.helpText), '');
    }

    //支持联级菜单，数据保存id 或 value
    private getHtmlForTaxonomy(thisDefs: FormField, dataStr: string, byValue: boolean) {
        let datas = thisDefs.customData.split('|');
        let typeId = datas[0];

        var ctrlStr = "";
        ctrlStr += "    <div class=\"form-group form-md-line-input form-md-floating-label no-hint\">";
        ctrlStr += "        <label>" + this._appLocalizationService.l(thisDefs.displayName) + "</label>";
        ctrlStr += "        <taxonomy-combo [byValue]=\""+(byValue?"true":"false") +"\" [(selectedValue)]=\""+dataStr + thisDefs.fieldName + "\"  ";
        var isMulti = false;
        var isRequired = false;
        if (thisDefs.security) {
            if (thisDefs.security.multiSeleted) {
                isMulti = true;
            }
            if (thisDefs.security.required) {
                isRequired = true;
            }
        }
        if (isMulti) {
            ctrlStr += " [multiple]=\"true\" ";
        } else if (!isRequired) {
            ctrlStr += " defaultValue=\"#\" ";
        }

        //customData： 非联级菜单传入 typeId，一级菜单 typeId|， 下级菜单typeId|str1 (str1是上一级数据的字段)
        // 详见 TaxonomyComboOption
        if(datas.length > 1){
            if(datas[1]){
                if(datas[1].length < 3){
                    // 直接拉取一个下级菜单
                    ctrlStr += " typeId=\"" + typeId + "|"+ datas[1] +"\"";
                }else{
                    // 联级菜单 的 下级菜单
                    ctrlStr += " [relateVal]=\""+dataStr + datas[1] +"\" ";
                }
            }else{
                // 联级菜单 的 一级菜单
                ctrlStr += " typeId=\"" + typeId + "|0\"";
            }
        }else{
            // 树状数据全拉
            ctrlStr += " typeId=\"" + typeId + "\"";
        }
        ctrlStr += " ></taxonomy-combo>";
        ctrlStr += "    </div>";

        return this.getColumnHtml(thisDefs, this.addhelpText(ctrlStr, thisDefs.helpText), '');
    }

    private getHtmlForInput(thisDefs: FormField, dataStr: string) {
        var ctrlStr = "";
        ctrlStr += "<div class=\"form-group form-md-line-input form-md-floating-label no-hint\">";
        if (thisDefs.security && thisDefs.security.maxLength) {
            ctrlStr += "<label>" + this._appLocalizationService.l(thisDefs.displayName) + "({{"+dataStr + thisDefs.fieldName+"?"+dataStr + thisDefs.fieldName+".length:0}}/"+thisDefs.security.maxLength+")</label> ";
        }else{
            ctrlStr += "<label>" + this._appLocalizationService.l(thisDefs.displayName) + "</label> ";
        }

        ctrlStr += "<input type=\"" + (thisDefs.ctrlType ? thisDefs.ctrlType : "text") + "\" class=\"form-control\" [ngClass]=\"{'edited':data." + thisDefs.fieldName + "}\"  "
        if (thisDefs.security) {
            if (thisDefs.security.required) {
                ctrlStr += " required ";
            }
            if (thisDefs.security.maxLength) {
                ctrlStr += " maxlength=\"" + thisDefs.security.maxLength + "\" ";
            }
        }
        ctrlStr += "  name=\"" + thisDefs.fieldName + "\"  [(ngModel)]=\""+dataStr + thisDefs.fieldName + "\"  ";
        if (thisDefs.special) {
            ctrlStr += " disabled ";
        }
        if(thisDefs.readOnly){
            ctrlStr += " readOnly "; 
        }
        ctrlStr += "/></div>";

        return this.getColumnHtml(thisDefs, this.addhelpText(ctrlStr, thisDefs.helpText), '');
    }

    private getHtmlForDateTime(thisDefs: FormField, dataStr: string) {
        let ctrlStr = "";

        if (thisDefs.ctrlType === "datepicker") {

            ctrlStr += "<div class=\"form-group form-md-line-input form-md-floating-label no-hint\">";
            ctrlStr += "<label>" + this._appLocalizationService.l(thisDefs.displayName) + "</label> ";

            ctrlStr += "    <input type=\"text\" readOnly=\"readOnly\" class=\"form-control edited\" name=\"" + thisDefs.fieldName + "\"  id=\"" + thisDefs.fieldName + "\" ";
            ctrlStr += " autocomplete=\"off\" [(date)]=\""+dataStr + thisDefs.fieldName + "\"  bsDatepicker datePickerLuxonModifier  [bsConfig]=\"{ adaptivePosition: true }\" ";
            if (thisDefs.security) {
                if (thisDefs.security.required) {
                    ctrlStr += " required ";
                }
            }
            if (thisDefs.special) {
                ctrlStr += " disabled ";
            }

            ctrlStr += "/></div>";

        } else if (thisDefs.ctrlType === "datetimepicker") {
            ctrlStr += "<div class=\"form-group form-md-line-input form-md-floating-label no-hint  input-group\">";
            ctrlStr += "<label>" + this._appLocalizationService.l(thisDefs.displayName) + "</label> ";

            ctrlStr += "    <flatpickr-ext addClass=\"form-control edited\" ctlName=\"" + thisDefs.fieldName + "\" [(date)]=\""+dataStr + thisDefs.fieldName + "\"  ";
            if (thisDefs.security) {
                if (thisDefs.security.required) {
                    ctrlStr += " required ";
                }
            }
            ctrlStr += "   [disableDate]=\"" + !!thisDefs.special + "\"></flatpickr-ext>";

            ctrlStr += "</div>";
        }

        return this.getColumnHtml(thisDefs, this.addhelpText(ctrlStr, thisDefs.helpText), '');
    }

    private getHtmlForNumber(thisDefs: FormField, dataStr: string) {
        var ctrlStr = "";
        ctrlStr += "<div class=\"form-group form-md-line-input form-md-floating-label no-hint\">";
        ctrlStr += "<label for=\"" + thisDefs.fieldName + "\">" + this._appLocalizationService.l(thisDefs.displayName) + "</label> ";
        ctrlStr += "<input type=\"number\" class=\"form-control edited\"  id=\"" + thisDefs.fieldName + "\"  name=\"" + thisDefs.fieldName + "\" [(ngModel)]=\""+dataStr + thisDefs.fieldName + "\" "
        if (thisDefs.security) {
            if (thisDefs.security.required) {
                ctrlStr += " required ";
            }
            if (thisDefs.security.minValue) {
                ctrlStr += " min=\"" + thisDefs.security.minValue + "\" ";
            }
            if (thisDefs.security.maxValue) {
                ctrlStr += " max=\"" + thisDefs.security.maxValue + "\" ";
            }
        }
        if (thisDefs.customData) {
            ctrlStr += " step=\"" + thisDefs.customData + "\" ";
        }
        ctrlStr += "> ";
        ctrlStr += "</div>";

        return this.getColumnHtml(thisDefs, this.addhelpText(ctrlStr, thisDefs.helpText), '');
    }

    private getHtmlForFile(thisDefs: FormField, dataStr: string, subKey: string) {
        let ctrlStr = "";
        let datas = thisDefs.customData.split('|');
        let customKey = datas[0];

        let alias = '';
        if(datas.length > 1){
            alias = datas[1];
        }

        let canEdit = '';
        if(datas.length > 2){
            let entityType = datas[2];
            if(entityType === 'Content'){
                canEdit = "permissionDic['Pages_Manage_Content_Create']||permissionDic['Pages_Manage_Content_Update']";
            }else if(entityType === 'ImageText'){
                canEdit = "permissionDic['Pages.Tenant.MenuInfo.ImageText.Create']||permissionDic['Pages.Tenant.MenuInfo.ImageText.Edit']";
            }else if(entityType === 'ExtendedData'){
                canEdit = "permissionDic['Pages.Tenant.MenuInfo.ExtendedData.Edit']";
            }
        }

        let randomIdStr = subKey? "randomId['"+subKey+"']":"randomId" ;
        let helpText = thisDefs.helpText ? thisDefs.helpText: '';
        let isTemporaryStr =  subKey? "isTemporary['"+subKey+"']":"isTemporary" ;

        if (thisDefs.ctrlType === "Single") {
            //单文件
            ctrlStr += "<div class='row margin-bottom-15'><label class=\"col-sm-2 control-label\">" + this._appLocalizationService.l(thisDefs.displayName) + ":</label>";
            ctrlStr += "    <single-upload class=\"col-sm-10\" [isTemporary]=\"" + isTemporaryStr + "\" [contentId]=\"" + randomIdStr + "\" customKey=\"" + customKey + "\" alias=\"" + alias + "\"";
            if(canEdit){
                ctrlStr += " [ctrlDisabled]=\"!("+canEdit+")\" ";
            }else{
                ctrlStr += " [ctrlDisabled]=\"true\" ";
            }
            ctrlStr += " description=\"" + helpText + "\" ></single-upload></div>";
        } 
        else if (thisDefs.ctrlType === "Single2") {

            //单文件
            ctrlStr += "<div class='row margin-bottom-15'>";
            ctrlStr += "    <single-upload2 class=\"col-sm-10\" customKey=\"" + customKey + "\" description=\"" + helpText + "\"";
            ctrlStr += " alias=\"" + alias + "\" uploadType=\"0\" isPreviewImg=\"false\" label=\""+this._appLocalizationService.l(thisDefs.displayName)+"\"  ";
            if(canEdit){
                ctrlStr += " [canEdit]=\""+canEdit+"\" ";
            }else{
                ctrlStr += " [canEdit]=\"false\" ";
            }
            ctrlStr += " [(picurl)]=\""+dataStr + thisDefs.fieldName + "\" ></single-upload2></div>";
        } 
        else {
            //多文件
            ctrlStr += "    <batch-upload displayName=\"" + this._appLocalizationService.l(thisDefs.displayName) + "\" [isTemporary]=\"" + isTemporaryStr + "\" [contentId]=\"" + randomIdStr + "\"";
            if(canEdit){
                ctrlStr += " [ctrlDisabled]=\"!("+canEdit+")\" ";
            }else{
                ctrlStr += " [ctrlDisabled]=\"true\" ";
            }
            ctrlStr += " autoSyncBySelf=\"false\" customKey=\"" + customKey + "\"></batch-upload>";
        }
        
        return this.getColumnHtml(thisDefs, ctrlStr, 'form-group');
    }

    async createFormComponentFactory(compiler: Compiler, templateStr: string, constructor: any, appendModules: any[] = null): Promise<ComponentFactory<any>> {
        //.log(templateStr);
        const tmpCmp = Component({ template: templateStr })(
            new constructor().constructor
        );

        let imports = [AppSharedModule, MainSharedModule,LayoutEditorModule];
        if(appendModules){
            imports = imports.concat(appendModules);
        }
        const tmpModule = NgModule({
            imports: imports,
            declarations: [tmpCmp],
            // providers: [] - e.g. if your dynamic component needs any service, provide it here.
        })(class { });

        let moduleWithComponentFactory = await compiler.compileModuleAndAllComponentsAsync(tmpModule);
        return moduleWithComponentFactory.componentFactories.find(x => x.componentType === tmpCmp);
    }
}